﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Apewer.Web
{

    internal sealed class MiniWriter : Stream
    {

        bool _disposed = false;

        MiniConnection _conn;
        Stream _stream;
        bool _chunked;

        internal MiniWriter(MiniConnection conn)
        {
            _conn = conn;
            _stream = conn.Stream;
            _chunked = conn.Chunked;
        }

        #region

        public bool Disposed { get => _disposed; }

        public override bool CanRead { get => false; }

        public override bool CanWrite { get => true; }

        public override bool CanSeek { get => false; }

        public override long Length { get => throw new NotSupportedException(); }

        public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }

        public override void Close() => _disposed = true;

        public override void Flush() { }

        public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();

        public override void SetLength(long value) => throw new NotSupportedException();

        public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException();

        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback cback, object state) => throw new NotSupportedException();

        public override int EndRead(IAsyncResult ar) => throw new NotSupportedException();

        #endregion

        #region write

        static readonly byte[] CRLF = BytesUtility.CRLF;

        byte[] Pack(byte[] buffer, int offset, int count)
        {
            if (_disposed) throw new ObjectDisposedException(typeof(Stream).FullName);

            // 检查参数。
            if (buffer == null) throw new ArgumentNullException("参数 buffer 无效。");
            if (offset < 0) throw new ArgumentOutOfRangeException("offset", "参数 offset 小于 0。");
            if (count < 0) throw new ArgumentOutOfRangeException("count", "参数 count 小于 0。");
            int bufferLength = buffer.Length;
            if (offset > bufferLength) throw new ArgumentOutOfRangeException("offset", "指定的 offset 的值超出了 buffer 数组的容量。");
            if (offset + count > bufferLength) throw new ArgumentException("指定的 offset 和 count 超出了 buffer 数组的容量。");

            // 分块。
            if (_chunked)
            {
                var ab = new ArrayBuilder<byte>(1024);
                ab.Add(count.ToString().Bytes());
                ab.Add(CRLF);
                ab.Add(buffer, offset, count);
                ab.Add(CRLF);
                ab.Add(CRLF);

                var block = ab.Export();
                return block;
            }
            else
            {
                var block = new byte[count];
                Buffer.BlockCopy(buffer, offset, block, 0, count);
                return block;
            }
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            var block = Pack(buffer, offset, count);
            if (_conn.Server.SynchronousIO)
            {
                _stream.Write(block, 0, block.Length);
            }
            else
            {
                var async = _stream.BeginWrite(block, 0, block.Length, null, null);
                _stream.EndWrite(async);
            }
        }

        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            var block = Pack(buffer, offset, count);
            return _stream.BeginWrite(buffer, offset, count, callback, state);
        }

        public override void EndWrite(IAsyncResult ar)
        {
            if (_disposed) throw new ObjectDisposedException(typeof(Stream).FullName);
            _stream.EndWrite(ar);
        }

        #endregion

    }

}
